package cn.elwy.rcp.ui.explorer.core.dao.impl;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import org.apache.commons.configuration.ConfigurationException;
import org.apache.commons.configuration.XMLConfiguration;
import org.apache.commons.configuration.tree.ConfigurationNode;
import org.springframework.stereotype.Repository;

import cn.elwy.common.exception.ConfigException;
import cn.elwy.common.i18n.Msg;
import cn.elwy.common.util.encode.SecurityUtil;
import cn.elwy.osgi.config.ConfigContext;
import cn.elwy.rcp.ui.explorer.core.dao.ProjectConfigDao;
import cn.elwy.rcp.ui.explorer.core.vo.FtpInfo;
import cn.elwy.rcp.ui.explorer.core.vo.ProjectConfig;

@Repository(ProjectConfigDao.ID)
public class ProjectConfigDaoImpl implements ProjectConfigDao {

  private static final String PWD_KEY = "com.yss.sofa";
  private static final String IP2 = ").ip";
  private static final String PORT2 = ").port";
  private static final String USER_NAME = ").userName";
  private static final String PASSWORD2 = ").password";
  private static final String DEPLOYS_DEPLOY = "deploys.deploy(";
  private static final String DEPLOY = "deploy";
  private static final String DEPLOYS_LOCATION = ")[@location]";
  private static final String DEPLOYS2 = "deploys";
  private static final String RELEASE_PASSWORD = "release.password";
  private static final String RELEASE_USER_NAME = "release.userName";
  private static final String RELEASE_PORT = "release.port";
  private static final String RELEASE_IP = "release.ip";
  private static final String RELEASE_LOCATION = "release[@location]";
  private static final String FILE_NAME = ")[@fileName]";
  private static final String PLANS_PLAN = "plans.plan(";
  private static final String PLAN = "plan";
  private static final String PLANS2 = "plans";
  private static final String PARENT_POM = "parentPom";
  private static final String TOOLS_PATH = "toolsPath";
  private static final String MVNCMD = "mvnCmd";
  private static final String WARPATH = "warPath";
  private static final String PACKTYPE = "packType";
  private static final String CONTAINER_DIRECTORY = "containerDirectory";
  private static final String DB_SCRIPT_DIRECTORY = "dbScriptDirectory";
  private static final String DBS_UPDATE_ORIGIN_DIR = "dbsUpdateOriginDir";
  private static final String DBS_UPDATE_TARGET_DIR = "dbsUpdateTargetDir";
  private static final String DEMO_DIRECTORY = "demoDirectory";
  private static final String SRC_DIRECTORY = "srcDirectory";
  private static final String DOC_DIRECTORY = "docDirectory";
  private static final String SOURCE_DIRECTORY = "sourceDirectory";
  private static final String END_VERSION = "endVersion";
  private static final String AUTO_UPDATE = "autoUpdate";
  private static final String UPDATE_START_VERSION = "updateStartVersion";
  private static final String ERROR_BREAK = "errorBreak";
  private static final String START_VERSION = "startVersion";
  private static final String SCM_TEST_SVN = "scm[@testSvn]";
  private static final String SCM_PASSWORD = "scm.password";
  private static final String SCM_USER = "scm.user";
  private static final String SCM_URL = "scm.url";
  private static final String OUTPUT_PATH = "outputPath";
  private static final String RESOURCE_PATH = "resourcePath";
  private static final String PATH2 = "[@path]";
  private static final String VERSION2 = "[@version]";
  private static final String NAME2 = "[@name]";
  private XMLConfiguration config;

  /**
   * 加载工程配置文件
   * @param projectPath 配置文件路径
   * @return
   */
  public ProjectConfig load(File file) {
    try {
      return load(new FileInputStream(file), ConfigContext.DEFAULT_ENCODING);
    } catch (Exception e) {
      throw new ConfigException(Msg.E_LOAD_CONFIG_ERROR, e);
    }
  }

  /**
   * 加载工程配置文件
   * @param file 配置文件路径
   * @return
   */
  public ProjectConfig load(URL url) {
    try {
      return load(url.openStream(), ConfigContext.DEFAULT_ENCODING);
    } catch (IOException e) {
      throw new ConfigException(Msg.E_LOAD_CONFIG_ERROR, e);
    } finally {

    }
  }

  /**
   * 加载工程配置文件
   * @param file 配置文件路径
   * @return
   */
  public ProjectConfig load(InputStream in, String encoding) {
    config = new XMLConfiguration();
    try {
      config.load(in);
      config.setEncoding(encoding);
    } catch (ConfigurationException e) {
      throw new ConfigException(Msg.E_LOAD_CONFIG_ERROR, e);
    }
    ProjectConfig pc = new ProjectConfig();
    String name = config.getString(NAME2);
    String version = config.getString(VERSION2);
    String path = config.getString(PATH2);
    String resourcePath = config.getString(RESOURCE_PATH);
    String outputPath = config.getString(OUTPUT_PATH);

    boolean testSvn = config.getBoolean(SCM_TEST_SVN, true);
    String scmUrl = config.getString(SCM_URL);
    String scmUser = config.getString(SCM_USER);
    String scmPassword = config.getString(SCM_PASSWORD);
    if (scmPassword != null) {
      try {
        scmPassword = SecurityUtil.decryptDES(scmPassword, PWD_KEY);
      } catch (Exception e) {
        e.printStackTrace();
      }
    }
    boolean autoUpdate = config.getBoolean(AUTO_UPDATE, false);
    boolean updateStartVersion = config.getBoolean(UPDATE_START_VERSION, false);
    boolean errorBreak = config.getBoolean(ERROR_BREAK, true);
    String startVersion = config.getString(START_VERSION);
    String endVersion = config.getString(END_VERSION);
    String sourceDirectory = config.getString(SOURCE_DIRECTORY);
    String docDirectory = config.getString(DOC_DIRECTORY);
    String demoDirectory = config.getString(DEMO_DIRECTORY);
    String srcDirectory = config.getString(SRC_DIRECTORY);
    String dbScriptDirectory = config.getString(DB_SCRIPT_DIRECTORY);
    String dbsUpdateOriginDir = config.getString(DBS_UPDATE_ORIGIN_DIR);
    String dbsUpdateTargetDir = config.getString(DBS_UPDATE_TARGET_DIR);
    String containerDirectory = config.getString(CONTAINER_DIRECTORY);
    String parentPom = config.getString(PARENT_POM);
    String toolsPath = config.getString(TOOLS_PATH);
    String mvnCmd = config.getString(MVNCMD);
    String warPath = config.getString(WARPATH);
    int packType = config.getInt(PACKTYPE, 0);

    pc.setProjectName(name);
    pc.setVersion(version);
    pc.setProjectPath(path);
    pc.setResourcePath(resourcePath);
    pc.setOutputPath(outputPath);
    pc.setTestSvn(testSvn);
    pc.setScmUrl(scmUrl);
    pc.setScmUser(scmUser);
    pc.setScmPassword(scmPassword);
    pc.setStartVersion(startVersion);
    pc.setUpdateStartVersion(updateStartVersion);
    pc.setAutoUpdate(autoUpdate);
    pc.setErrorBreak(errorBreak);
    pc.setEndVersion(endVersion);
    pc.setSourceDirectory(sourceDirectory);
    pc.setDocDirectory(docDirectory);
    pc.setDemoDirectory(demoDirectory);
    pc.setSrcDirectory(srcDirectory);
    pc.setDbScriptDirectory(dbScriptDirectory);
    pc.setDbsUpdateOriginDir(dbsUpdateOriginDir);
    pc.setDbsUpdateTargetDir(dbsUpdateTargetDir);
    pc.setContainerDirectory(containerDirectory);
    pc.setParentPom(parentPom);
    pc.setToolsPath(toolsPath);
    pc.setMvnCmd(mvnCmd);
    pc.setWarPath(warPath);
    pc.setPackType(packType);

    ConfigurationNode rootNode = config.getRootNode();
    List<ConfigurationNode> plans = rootNode.getChildren(PLANS2);
    int planCount = plans.get(0).getChildrenCount(PLAN);
    List<String> planList = new ArrayList<String>();
    for (int i = 0; i < planCount; i++) {
      String fileName = config.getString(PLANS_PLAN + i + FILE_NAME);
      planList.add(fileName);
    }
    pc.setPlanList(planList);

    {
      FtpInfo release = new FtpInfo();
      String location = config.getString(RELEASE_LOCATION);
      String ip = config.getString(RELEASE_IP);
      int port = config.getInt(RELEASE_PORT, 0);
      String userName = config.getString(RELEASE_USER_NAME);
      String password = config.getString(RELEASE_PASSWORD);
      release.setLocation(location);
      release.setIp(ip);
      release.setPort(port);
      release.setUserName(userName);
      release.setPassword(password);
      pc.setRelease(release);
    }

    List<ConfigurationNode> deploys = rootNode.getChildren(DEPLOYS2);
    int deployCount = deploys.get(0).getChildrenCount(DEPLOY);
    List<FtpInfo> deployList = new ArrayList<FtpInfo>();
    for (int i = 0; i < deployCount; i++) {
      FtpInfo ftpInfo = new FtpInfo();
      String ip = config.getString(DEPLOYS_DEPLOY + i + IP2);
      int port = config.getInt(DEPLOYS_DEPLOY + i + PORT2, 0);
      String userName = config.getString(DEPLOYS_DEPLOY + i + USER_NAME);
      String password = config.getString(DEPLOYS_DEPLOY + i + PASSWORD2);
      ftpInfo.setIp(ip);
      ftpInfo.setPort(port);
      ftpInfo.setUserName(userName);
      ftpInfo.setPassword(password);
      ftpInfo.setName("");
      deployList.add(ftpInfo);
    }
    pc.setDeployList(deployList);

    return pc;
  }

  public ProjectConfig getEmptyPorject() {
    ProjectConfig appServer = new ProjectConfig();
    appServer.setProjectName("");
    appServer.setVersion("");
    appServer.setProjectPath("");
    appServer.setResourcePath("");
    appServer.setOutputPath("");
    appServer.setStartVersion("");
    appServer.setEndVersion("");
    appServer.setSourceDirectory("");
    appServer.setDocDirectory("");
    appServer.setDemoDirectory("");
    appServer.setSrcDirectory("");
    appServer.setDbScriptDirectory("");
    appServer.setContainerDirectory("");
    appServer.setParentPom("");
    appServer.setToolsPath("");
    appServer.setTestSvn(true);
    appServer.setAutoUpdate(true);
    appServer.setErrorBreak(true);
    appServer.setScmUrl("");
    appServer.setScmUser("");
    appServer.setScmPassword("");
    appServer.setMvnCmd("");
    appServer.setWarPath("");
    appServer.setPlanList(Collections.<String> emptyList());
    appServer.setRelease(null);
    appServer.setDeployList(Collections.<FtpInfo> emptyList());
    return appServer;
  }

  public void save(ProjectConfig projectConfig, File file) {
    config.setProperty(NAME2, projectConfig.getProjectName());
    config.setProperty(VERSION2, projectConfig.getVersion());
    config.setProperty(PATH2, projectConfig.getProjectPath());
    config.setProperty(RESOURCE_PATH, projectConfig.getResourcePath());
    config.setProperty(OUTPUT_PATH, projectConfig.getOutputPath());
    config.setProperty(SCM_TEST_SVN, projectConfig.isTestSvn());
    config.setProperty(SCM_URL, projectConfig.getScmUrl());
    config.setProperty(SCM_USER, projectConfig.getScmUser());
    String scmPassword = projectConfig.getScmPassword();
    if (scmPassword != null) {
      scmPassword = SecurityUtil.encryptDES(scmPassword, PWD_KEY);
    }
    config.setProperty(SCM_PASSWORD, scmPassword);
    config.setProperty(AUTO_UPDATE, projectConfig.isAutoUpdate());
    config.setProperty(UPDATE_START_VERSION, projectConfig.isUpdateStartVersion());
    config.setProperty(ERROR_BREAK, projectConfig.isErrorBreak());
    config.setProperty(START_VERSION, projectConfig.getStartVersion());
    config.setProperty(END_VERSION, projectConfig.getEndVersion());
    config.setProperty(SOURCE_DIRECTORY, projectConfig.getSourceDirectory());
    config.setProperty(DOC_DIRECTORY, projectConfig.getDocDirectory());
    config.setProperty(DEMO_DIRECTORY, projectConfig.getDemoDirectory());
    config.setProperty(SRC_DIRECTORY, projectConfig.getSrcDirectory());
    config.setProperty(DB_SCRIPT_DIRECTORY, projectConfig.getDbScriptDirectory());
    config.setProperty(DBS_UPDATE_ORIGIN_DIR, projectConfig.getDbsUpdateOriginDir());
    config.setProperty(DBS_UPDATE_TARGET_DIR, projectConfig.getDbsUpdateTargetDir());
    config.setProperty(CONTAINER_DIRECTORY, projectConfig.getContainerDirectory());
    config.setProperty(PARENT_POM, projectConfig.getParentPom());
    config.setProperty(TOOLS_PATH, projectConfig.getToolsPath());
    config.setProperty(MVNCMD, projectConfig.getMvnCmd());
    config.setProperty(WARPATH, projectConfig.getWarPath());
    config.setProperty(PACKTYPE, projectConfig.getPackType());

    List<String> planList = projectConfig.getPlanList();
    for (int i = 0; i < planList.size(); i++) {
      config.setProperty(PLANS_PLAN + i + FILE_NAME, planList.get(i));
    }

    FtpInfo release = projectConfig.getRelease();
    if (release != null) {
      config.setProperty(RELEASE_LOCATION, release.getLocation());
      config.setProperty(RELEASE_IP, release.getIp());
      config.setProperty(RELEASE_PORT, release.getPort());
      config.setProperty(RELEASE_USER_NAME, release.getUserName());
      config.setProperty(RELEASE_PASSWORD, release.getPassword());
    }

    List<FtpInfo> deployList = projectConfig.getDeployList();
    if (deployList != null) {
      for (int i = 0; i < deployList.size(); i++) {
        FtpInfo deploy = deployList.get(i);
        config.setProperty(DEPLOYS_DEPLOY + i + DEPLOYS_LOCATION, deploy.getLocation());
        config.setProperty(DEPLOYS_DEPLOY + i + IP2, deploy.getIp());
        config.setProperty(DEPLOYS_DEPLOY + i + PORT2, deploy.getPort());
        config.setProperty(DEPLOYS_DEPLOY + i + USER_NAME, deploy.getUserName());
        config.setProperty(DEPLOYS_DEPLOY + i + PASSWORD2, deploy.getPassword());
      }
    }
    try {
      file.getParentFile().mkdirs();
      config.save(file);
    } catch (ConfigurationException e) {
      throw new ConfigException(e.getMessage(), e);
    }
  }

}
